package com.joven.shelltest.utils;

import ch.qos.logback.classic.pattern.MessageConverter;
import ch.qos.logback.classic.spi.ILoggingEvent;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.CollectionUtils;

import java.util.HashSet;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 自定义日志脱敏
 * @Author wzj
 * @Date 2023-08-11 10:19
 **/
public class SensitiveLogDataConverter extends MessageConverter {
    //银行卡正则匹配
    private final static Pattern BANK_CARD_PATTERN = Pattern.compile("(\\D)([3-6]\\d{3})(\\d{8,12})(\\d{4})(\\D)", Pattern.CASE_INSENSITIVE);

    //手机号正则匹配
    private final static Pattern PHONE_PATTERN = Pattern.compile("(?<!\\d)(1\\d{10})(?!\\d)", Pattern.CASE_INSENSITIVE);

    //身份证正则匹配
    private final static Pattern ID_CARD_PATTERN = Pattern.compile("([1-9]\\d{5}(18|19|20)\\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\\d{3}[\\dXx])|([1-9]\\d{5}\\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\\d{3})", Pattern.CASE_INSENSITIVE);

    //姓名正则匹配
    //姓名、realName 暂时不加密
    private final static Pattern NAME_PATTERN = Pattern.compile("(userName|receiveName)(=|=\\[|\\\":\\\"|:|：|=')([\\u4e00-\\u9fa5]{1})([\\u4e00-\\u9fa5]{1,3})(\\]|\\\"|'|)", Pattern.CASE_INSENSITIVE);

    //邮箱
    private final static Pattern EMAIL_PATTERN = Pattern.compile("(\\w{1})(\\w*)(\\w{1})@(\\w+)(.com)", Pattern.CASE_INSENSITIVE);

    //其他（密码/地址/卡号等）
    private final static Pattern OTHER_PATTERN = Pattern.compile("(appId|authCode|password|密码|验证码|地址|住址|address|cardNo|卡号|card|cardNumber|app_key|appkey|appSecret|app_secret)(=|=\\[|\\\":\\\"|:|：|=')(.*?)(?>(\\]|[^\\\\\"]\\\"|'))", Pattern.CASE_INSENSITIVE);

    @Override
    public String convert(ILoggingEvent event) {
        try {
            final Set<String> list;
            String logMsg = event.getFormattedMessage();
            list = validDate(logMsg);
            if (!CollectionUtils.isEmpty(list)) {
                for (String param : list) {
                    String convertMsg = logMsg;
                    logMsg = convertDate(convertMsg, param);
                }
            }
            return logMsg;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return super.convert(event);
    }

    /**
     * 正则匹配是否包含脱敏数据
     */
    private static Set<String> validDate(String param) {
        Set<String> set = new HashSet<>();
        // 匹配手机号
        Matcher phoneMatcher = PHONE_PATTERN.matcher(param);
        while (phoneMatcher.find()) {
            set.add(phoneMatcher.group());
        }
        // 匹配身份证
        Matcher idCardMatcher = ID_CARD_PATTERN.matcher(param);
        while (idCardMatcher.find()) {
            set.add(idCardMatcher.group());
        }

        Matcher bankCardMatcher = BANK_CARD_PATTERN.matcher(param);
        while (bankCardMatcher.find()) {
            set.add(bankCardMatcher.group());
        }

        Matcher namePatternMatcher = NAME_PATTERN.matcher(param);
        while (namePatternMatcher.find()) {
            set.add(namePatternMatcher.group());
        }


        Matcher emailPatternMatcher = EMAIL_PATTERN.matcher(param);
        while (emailPatternMatcher.find()) {
            set.add(emailPatternMatcher.group());
        }

        Matcher otherPatternMatcher = OTHER_PATTERN.matcher(param);
        while (otherPatternMatcher.find()) {
            set.add(otherPatternMatcher.group());
        }
        return set;
    }

    /**
     * 数据脱敏
     */
    private static String convertDate(String logMsg, String param) {

        if (PHONE_PATTERN.matcher(param).find()) {
            return logMsg.replace(param, param.replaceAll("(\\d{3})\\d{4}(\\d{4})", "$1****$2"));
        } else if (ID_CARD_PATTERN.matcher(param).find()) {
            String replaceContext = param.replaceAll(param, StringUtils.left(param, 6).concat(StringUtils.removeStart(StringUtils.leftPad(StringUtils.right(param, 4), StringUtils.length(param), "*"), "******")));
            return logMsg.replace(param, replaceContext);
        } else if (BANK_CARD_PATTERN.matcher(param).find()) {
            String replaceContext = BANK_CARD_PATTERN.matcher(param).replaceAll("$1$2********$4$5");
            return logMsg.replace(param, replaceContext);
        } else if (NAME_PATTERN.matcher(param).find()) {
            String replaceContext = NAME_PATTERN.matcher(param).replaceAll("$1$2$3**$5");
            return logMsg.replace(param, replaceContext);
        } else if (EMAIL_PATTERN.matcher(param).find()) {
            String replaceContext = EMAIL_PATTERN.matcher(param).replaceAll("$1****$3@$4.com");
            return logMsg.replace(param, replaceContext);
        } else if (OTHER_PATTERN.matcher(param).find()) {
            String replaceMent = "$1$2********$4";
            String replaceContext = OTHER_PATTERN.matcher(param).replaceAll(replaceMent);
            return logMsg.replace(param, replaceContext);
        }
        return logMsg;
    }

}
